<?php

namespace KyleWechat;

use KyleWechat\Exception\InvalidParamException;
use KyleWechat\MiniProgram\MiniProgram;
use KyleWechat\Wechat\Wechat;
use ReflectionClass;
use ReflectionException;

/**
 *
 * @property WechatServer $app
 * @property Wechat $wechat
 * @property MiniProgram $miniProgram
 */
class WechatServer
{
    /**
     * @var Config
     */
    public $config;

    /**
     * @var WechatServer
     */
    protected static $instance;

    protected $bind = [
        'app' => WechatServer::class,
        'wechat' => Wechat::class,
        'miniProgram' => MiniProgram::class
    ];

    /**
     * @param $appid
     * @param $secret
     * @return WechatServer
     * @throws Exception\InvalidConfigException
     */
    public static function getInstance($appid, $secret): WechatServer
    {
        static::$instance = new static();
        static::$instance->config = new Config($appid,$secret);
        static::$instance->setInstance();
        return static::$instance;
    }

    public static function getApp(): WechatServer
    {
        return static::$instance;
    }

    private function setInstance()
    {
        $this->bind['app'] = $this;
    }

    /**
     * @return mixed
     * @throws ReflectionException
     */
    public function make(string $abstract, array $vars = [])
    {
        if (isset($this->bind[$abstract]) && is_object($this->bind[$abstract])) {
            return $this->bind[$abstract];
        }
        try {
            $class = $this->bind[$abstract] ?? $abstract;
            $reflect = new ReflectionClass($class);
        } catch (ReflectionException $e) {
            throw new InvalidParamException('class not exists: ' . $class, $class, $e);
        }
        return $reflect->newInstanceArgs($vars);
    }

    public function __set($name, $value)
    {
        $this->bind[$name] = $value;
    }

    /**
     * @throws ReflectionException
     */
    public function __get(string $name)
    {
        return $this->make($name);
    }
}